/*
 * RtmpCaster.cpp
 *
 *  Created on: 2016年9月15日
 *      Author: zhengboyuan
 */

#include "BasicType.h"
#include "RtmpCaster.h"
#include "Application.h"
#include "CRtmpMediaCaster.h"
#include "CLog.h"
#include "RtmpCasterName.h"
#include "MediaFormatUtil.h"
#include "RtmpCasterConfig.h"

static Application& app()
{
	return Application::instance();
}



void copyFormatFrom(av::MediaFormat& mfmt, const MFormat* fmt)
{
    mfmt.m_codec = fmt->codec;
    mfmt.m_width= fmt->width;
    mfmt.m_height = fmt->height;
    mfmt.m_framerate = fmt->framerate;
    mfmt.m_profile = fmt->profile;
    mfmt.m_clockRate = fmt->clockRate;
	mfmt.m_bitrate = fmt->bitrate;

    mfmt.m_audioCodec = fmt->audioCodec;
    mfmt.m_channels = fmt->channels;
    mfmt.m_sampleRate = fmt->sampleRate;
    mfmt.m_audioProfile = fmt->audioProfile;
    mfmt.m_audioRate = fmt->audioRate;
	mfmt.m_audioBitrate = fmt->audioBitrate;

    if (fmt->vProp && fmt->vPropSize > 0)
    {
        mfmt.m_videoProp.assign((char*)fmt->vProp, fmt->vPropSize);
    }

	if (fmt->config && fmt->configSize > 0)
	{
		mfmt.m_audioConfig.assign((char*)fmt->config, fmt->configSize);
	}
}

void copyFormatTo(const av::MediaFormat& mfmt, MFormat* fmt)
{
    fmt->codec = mfmt.m_codec;
    fmt->width = mfmt.m_width;
    fmt->height = mfmt.m_height;
    fmt->framerate = mfmt.m_framerate;
    fmt->profile = mfmt.m_profile;
    fmt->clockRate = mfmt.m_clockRate;
	fmt->bitrate = mfmt.m_bitrate;

    fmt->audioCodec = mfmt.m_audioCodec;
    fmt->channels = mfmt.m_channels;
    fmt->sampleRate = mfmt.m_sampleRate;
    fmt->audioProfile = mfmt.m_audioProfile;
    fmt->audioRate = mfmt.m_audioRate;
	fmt->audioBitrate = mfmt.m_audioBitrate;

    fmt->vProp = (uint8_t*)mfmt.m_videoProp.c_str();
    fmt->vPropSize = mfmt.m_videoProp.size();

}








/**
 * 初始化
 * @return
 */
DLLEXPORT int rtmpcaster_init()
{
	app().init();
	
	CLog::info("rtmpcaster_init\n");
	return 0;
}

/**
 * 反初始化
 * @return
 */
DLLEXPORT void rtmpcaster_quit()
{
	app().quit();
}


/**
 * 打开通道
 * @param handle 返回的通道句柄
 * @param url	推送地址
 * @param fmt   媒体格式
 * @return 0 表示成功
 */
DLLEXPORT int rtmpcaster_open(caster_t* handle, const char* url, const MFormat* fmt)
{
	if (!handle)
	{
		return EINVAL;
	}

	if (!url || (strlen(url) == 0))
	{
		return EINVAL;
	}

	if (!fmt)
	{
		return EINVAL;
	}

	CLog::debug("rtmpcaster_open. url: %s\n", url);
	CLog::debug("video format. codec: %d, width:%d, height:%d, clock:%d\n",
		fmt->codec, fmt->width, fmt->height, fmt->clockRate);
	CLog::debug("audio format. codec:%d, channels:%d, freq:%d, clock:%d\n",
		fmt->audioCodec, fmt->channels, fmt->sampleRate, fmt->audioRate);

	if ((fmt->codec != MCODEC_NONE) && (fmt->codec != MCODEC_H264))
	{
		CLog::warning("such codec is not supported. codec:%d\n", fmt->codec);
		return EINVAL;
	}
	
	MediaCasterPtr caster(new av::CRtmpMediaCaster());
	av::MediaFormat mfmt;
	copyFormatFrom(mfmt, fmt);

	int ret = caster->open(mfmt, url);
	if (ret != 0)
	{
		return ret;
	}

	*handle = app().put(caster);

	caster->setID(*handle);

	CLog::debug("rtmpcaster_open end. handle: %d\n", *handle);

	return 0;
}

/**
 * 关闭通道
 * @param handle 通道句柄
 */
DLLEXPORT void rtmpcaster_close(caster_t handle)
{
	CLog::debug("rtmpcaster_close. handle: %d\n", handle);

	MediaCasterPtr caster = app().remove(handle);
	if (caster)
	{
		caster->close();
	}
}


/**
 * 写媒体数据
 * @param handle
 * @param pkt		媒体包
 * @return
 */
DLLEXPORT int rtmpcaster_write(caster_t handle, const MPacket* packet)
{
	if (!packet || !packet->data)
	{
		return EINVAL;
	}
	
	if (handle == INVALID_CASTER)
	{
		return EINVAL;
	}

	MediaCasterPtr caster = app().get(handle);
	if (!caster)
	{
		return ENOENT;
	}
	
	av::MediaPacketPtr pkt(new av::MediaPacket());
	pkt->write(packet->data, packet->size);
	pkt->type = packet->type;
	pkt->pts = packet->pts;
	pkt->duration = packet->duration;
	pkt->flags = packet->flags;

	caster->write(pkt);

	return 0;
}



/**
 * 设置事件回调句柄
 * @param cb		回调函数指针
 * @param context	回调环境
 * @return 0 表示成功
 */
DLLEXPORT int rtmpcaster_set_event_callback(caster_t handle, CasterEventCallback cb, void* context)
{
	CLog::debug("rtmpcaster_set_event_callback. handle: %d, cb:%p\n", handle, cb);

	MediaCasterPtr caster = app().get(handle);
	if (!caster)
	{
		return ENOENT;
	}

	caster->setCallback(cb, context);

	return 0;
}

DLLEXPORT const char* rtmpcaster_get_event_name(int event)
{
	return av::RtmpCasterName::getEventName(event);
}

DLLEXPORT int rtmpcaster_set_queue_size(int size)
{
	if (size < 16)
	{
		return EINVAL;
	}

	av::RtmpCasterConfig::QUEUE_SIZE = size;
	av::RtmpCasterConfig::QUEUE_IDLE_SIZE = av::RtmpCasterConfig::QUEUE_SIZE / 4;

	return 0;
}

DLLEXPORT int rtmpcaster_set_retry_interval(int seconds)
{
	if (seconds < 0)
	{
		return EINVAL;
	}

	av::RtmpCasterConfig::RECONNECT_ELAPSE = seconds;
	return 0;
}

DLLEXPORT void rtmpcaster_set_stack_size(int stackSize)
{
    if (stackSize < 0)
    {
        return;
    }

    av::RtmpCasterConfig::STACK_SIZE = stackSize;
}